from datetime import date
from django.core.exceptions import ObjectDoesNotExist
from django.db import models


BOOK_STATUSES = (
    ('NOT READ', 'Not read'),
    ('IN PROGRESS', 'In progress'),
    ('FINISHED', 'Finished'),
)


class Book(models.Model):
    title = models.CharField(max_length=255)
    pages = models.IntegerField()
    toc_file = models.FileField(upload_to='toc_files/')
    date_added = models.DateField(auto_now_add=True)
    date_started = models.DateField(null=True, blank=True)
    date_finished = models.DateField(null=True, blank=True)
    status = models.CharField(max_length=20, choices=BOOK_STATUSES)
    max_level = models.IntegerField(blank=True, null=True)


    def save(self, *args, **kwargs):
        if not self.pk: # insert
            super(Book, self).save(*args, **kwargs)
            max_level = 0
            for line in self.toc_file:
                line = line.strip()
                words = line.split()
                level, title, page = len(words[0]), ' '.join(words[1:-1]), words[-1]
                TOCEntry.objects.create(book=self, level=level, title=title, page=page)
                if level > max_level:
                    max_level = level
            self.max_level = max_level
            super(Book, self).save(*args, **kwargs)
        else: # update
            if self.percent_entries_read() == 100:
                self.status = 'FINISHED'
                if not self.date_finished:
                    self.date_finished = date.today()
            elif not self.percent_entries_read():
                self.status = 'NOT READ'
                self.date_started, self.date_finished = None, None
            else:
                self.status = 'IN PROGRESS'
                self.date_finished = None
                if not self.date_started:
                    self.date_started = date.today()

            super(Book, self).save(*args, **kwargs)


    def entries_read(self):
        return self.entries.filter(read=True).count()


    def entries_total(self):
        return self.entries.count()


    def percent_entries_read(self):
        return 100 * float(self.entries_read()/float(self.entries_total()))


    def pages_read(self):
        if self.percent_entries_read() == 100:
            return self.pages

        total_read = 0
        for entry in self.entries.filter(read=True):
            try:
                next_entry_page = TOCEntry.objects.get(id=entry.id+1, book=self).page
            except ObjectDoesNotExist: # last entry
                next_entry_page = self.pages
            total_read += next_entry_page - entry.page
        return total_read

    
    def percent_pages_read(self):
        return 100 * float(self.pages_read() / float(self.pages))


    def pages_per_day(self):
        if self.date_started and self.date_finished:
            days = (self.date_finished - self.date_started).days
            return self.pages / float(days)
        elif self.date_started:
            days = (date.today() - self.date_started).days
            return self.pages / float(days)
        else:
            return None


    def __unicode__(self):
        return self.title



class TOCEntry(models.Model):
    book = models.ForeignKey(Book, related_name='entries')
    title = models.CharField(max_length=255)
    level = models.IntegerField()
    page = models.IntegerField()
    read = models.BooleanField(default=False)


    def inv_level(self):
        return self.book.max_level - self.level + 1

        
    def __unicode__(self):
        return self.title


    class Meta:
        ordering = ['id']
